Skip to content

Junaed/fssdk 10777 ssr doc update#318

Open
junaed-optimizely wants to merge 10 commits into3.x.xfrom
junaed/fssdk-10777-ssr-doc-update
Open

Junaed/fssdk 10777 ssr doc update#318
junaed-optimizely wants to merge 10 commits into3.x.xfrom
junaed/fssdk-10777-ssr-doc-update

Conversation

@junaed-optimizely
Copy link
Contributor

Summary

This pull request improves the documentation and implementation of server-side rendering (SSR) and ODP segment handling in the Optimizely React SDK V3.

It clarifies SSR usage in the README, adds a comprehensive Next.js integration guide, and updates the SDK's hooks to support more accurate decision-making during partial readiness states (such as when ODP segments are still being fetched). It also enhances test coverage for these scenarios.

Documentation improvements:

  • Expanded and clarified the SSR section in README.md to explain the need for a pre-fetched datafile, updated setup instructions, and added a summary of SSR limitations. References to Next.js and React Server Components were added, and the SSR example was simplified.
  • Added a new docs/nextjs-ssr.md guide detailing integration patterns for both Next.js App Router and Pages Router, including code examples, feature flag usage, server component usage, and SSR limitations.

SDK logic and behavior changes:

  • Updated the useExperiment, useFeature, and useDecision hooks to support synchronous decisions when getOptimizelyConfig and getUserContext are available, even if the client is not fully ready (e.g., ODP segments are still loading). This enables partial decisions during SSR or while waiting for async user/segment data. [1] [2] [3]

Testing improvements:

  • Enhanced test mocks in Experiment.spec.tsx, Feature.spec.tsx, and hooks.spec.tsx to include getOptimizelyConfig and getUserContext methods, simulating partial readiness and ODP scenarios. [1] [2] [3]
  • Added and updated tests to verify that hooks and components re-render with updated decisions once ODP segment fetching completes, ensuring correct feature flag behavior during partial readiness. [1] [2] [3]

Minor documentation and formatting fixes:

  • Cleaned up code samples and formatting in README.md for clarity and consistency. [1] [2] [3] [4] [5]

These changes make SSR and ODP segment handling more robust and developer-friendly, especially for teams using Next.js or requiring partial readiness support.

Test plan

Issues

  • FSSDK-10777

Copy link
Contributor

@raju-opti raju-opti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments

const isServer = typeof window === 'undefined';

const fetch = require('node-fetch');
const optimizelyClient = createInstance({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this assumes a new instance is created per request. Would be good to document the code example to include the instane creation using the following pattern:

function App() {
  const [optimizely] = useState(() => createInstacne({ });
  return <OptimizelyProvider optimizely={optimizely}> child </OptimizelyProvider>
}

datafileOptions: { autoUpdate: !isServer },
eventBatchSize: isServer ? 1 : 10,
eventMaxQueueSize: isServer ? 1 : 100,
// Optional: disable decision events on server if they will be sent from the client
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think odp event manager also has background timers, need to provided appropriate option for that

// src/data/getDatafile.ts
const CDN_URL = `https://cdn.optimizely.com/datafiles/${process.env.NEXT_PUBLIC_OPTIMIZELY_SDK_KEY}.json`;

export async function getDatafile() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one potential issue with this is that the ssr rendered component will basically always use the statically fetched datafile that was fetched at the beginning. The server side is expected to run for long time and it would miss updates. Basically this function need to pool the datafile as well. But since the sdk already has polling, this function can just use the SDK to do the polling,

// all other options can be turned off, this is just for polling datafile
const pollingInstance = createInstance({ sdkKey }); 

export async function getDatafile() {
  await pollingInstance.onReady();
  return pollingInstance.getOptimizelyConfig().getDatafile();
}

const [optimizely] = useState(() => {
const isServer = typeof window === 'undefined';
return createInstance({
datafile,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be good to include the sdkKey as well (would be used for config updaes in the client side)


- **Datafile required** — SSR requires a pre-fetched datafile. Using `sdkKey` alone falls back to a failed decision.
- **Static user only** — User `Promise` is not supported during SSR.
- **ODP segments unavailable** — ODP audience segments require async I/O and are not available during server rendering.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since there is a change in the hooks.ts file, I assume we need a patch update. In that case, can we consider adding the option to pass pre-fetched qualifiedSegments as props to the release?


```tsx
// pages/index.tsx
export async function getServerSideProps() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar here as the app router. instead of fetching on every request, we can have one optimizely instance for polling and get the datafile form the instance

}
```

### Static user only
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Static user only might suggest user cannot be changed, maybe use User Promise not supported?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants